/* 
 *  Copyright (C) 2006 Dip. Ing. dell'Informazione, University of Pisa, Italy
 *  http://info.iet.unipi.it/~cng/ns2measure/ns2measure.html
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, USA
 */

/**
   project: measure
   filename: loader.cc
	author: C. Cicconetti <c.cicconetti@iet.unipi.it>
	year: 2006
   affiliation:
      Dipartimento di Ingegneria dell'Informazione
	   University of Pisa, Italy
   description:
	   loader stand-alone utility
*/

#include <sys/types.h>   // UNIX includes
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>

#include <cstdlib>       // standard C includes
#include <cstdio>

#include <fstream>       // standard C++ includes
#include <iostream>
#include <string>
#include <set>

#define MAX_BUF 256

using namespace std;

int
main (int argc, char* argv[])
{
	unsigned int command; // command from analyze

	// check command line arguments
	if ( argc <= 3 ) {
		cout << "usage: " << argv[0] << " input output <ns2 command line>\n"
			<< "\nexample:\n"
			<< "\t" << argv[0] << " fifo1 fifo2 /usr/local/bin/ns2 myscen.tcl\n";
		exit (0);
	}

	// copy the arguments from the command line into ns2args
	char** ns2args = new char*[ argc - 3 + 4 ];
	for ( int i = 3 ; i < argc ; i++ )
		ns2args[i - 3] = argv[i];

	// add to the arguments list to ns2 the -out and -run options
	char ns2out[] = "-out";
	char ns2run[] = "-run";
	char ns2runID[MAX_BUF];
	ns2args[argc - 3 + 0] = ns2out;
	ns2args[argc - 3 + 1] = argv[2];
	ns2args[argc - 3 + 2] = ns2run;
	
	// open input data file from the analyze program
	int infile = open ( argv[1], O_RDONLY );
	if ( infile < 0 ) {
		cout << "Could not open '" << argv[1] << "' for reading. Terminating.\n";
		exit (0);
	}

	// read the set of saved runs, if any, and store them into the set of runs
	set<unsigned int> runs;
	unsigned int nruns;
	read ( infile, &nruns, sizeof(nruns));
	for ( unsigned int i = 0 ; i < nruns ; i++ ) { 
		read ( infile, &command, sizeof(command));
		runs.insert (command);
	}

	// run simulations until 0 is read from the analyze program
	for ( unsigned int run = 0 ; ; run++ ) {
		// skip any run identifier which has been already analyzed
		if ( runs.count (run) > 0 ) continue;

		// read command from the analyze program
		read ( infile, &command, sizeof(command));
		if ( command == 0 ) break;

		// run a simulation
		pid_t pid = fork ();
		if ( pid == 0 ) { // child
			// run simulation
			sprintf (ns2runID, "%d", run);
			ns2args[argc - 3 + 3] = ns2runID;
			
			if ( execv (ns2args[0], ns2args) == -1 ) {
				cout << "Could not exec '" << argv[3] << "'. Terminating\n";
				exit (0);
			}
		}
		int status = 0;
		wait(&status);
		if ( WIFEXITED(status) == false ||
		     ( WIFEXITED(status) == true && WEXITSTATUS(status) == 1 ) ) {
			cout << "An error has been detected. Invalid return code from NS-2" << endl;
			cout << "Status: " << status << ", WIFEXITED: " << WIFEXITED(status);
			cout << ", WEXITSTATUS: " << WEXITSTATUS(status) << endl;
			cout << "Terminating..." << endl;
			close (infile);
			exit(0);
		}
	}

	close (infile);
	exit (1);
}
